//===- AArch64SchedPredicates.td - AArch64 Sched Preds -----*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines scheduling predicate definitions that are used by the
// AArch64 subtargets.
//
//===----------------------------------------------------------------------===//

// Function mappers.

// Check the extension type in arithmetic instructions.
let FunctionMapper = "AArch64_AM::getArithExtendType" in {
  def CheckExtUXTB                      : CheckImmOperand_s<3, "AArch64_AM::UXTB">;
  def CheckExtUXTH                      : CheckImmOperand_s<3, "AArch64_AM::UXTH">;
  def CheckExtUXTW                      : CheckImmOperand_s<3, "AArch64_AM::UXTW">;
  def CheckExtUXTX                      : CheckImmOperand_s<3, "AArch64_AM::UXTX">;
  def CheckExtSXTB                      : CheckImmOperand_s<3, "AArch64_AM::SXTB">;
  def CheckExtSXTH                      : CheckImmOperand_s<3, "AArch64_AM::SXTH">;
  def CheckExtSXTW                      : CheckImmOperand_s<3, "AArch64_AM::SXTW">;
  def CheckExtSXTX                      : CheckImmOperand_s<3, "AArch64_AM::SXTX">;
}

// Check for shifting in extended arithmetic instructions.
foreach I = {0-3} in {
  let FunctionMapper = "AArch64_AM::getArithShiftValue" in
  def CheckExtBy#I                      : CheckImmOperand<3, I>;
}

// Check the extension type in the register offset addressing mode.
let FunctionMapper = "AArch64_AM::getMemExtendType" in {
  def CheckMemExtUXTW                   : CheckImmOperand_s<3, "AArch64_AM::UXTW">;
  def CheckMemExtLSL                    : CheckImmOperand_s<3, "AArch64_AM::UXTX">;
  def CheckMemExtSXTW                   : CheckImmOperand_s<3, "AArch64_AM::SXTW">;
  def CheckMemExtSXTX                   : CheckImmOperand_s<3, "AArch64_AM::SXTX">;
}

// Check for scaling in the register offset addressing mode.
let FunctionMapper = "AArch64_AM::getMemDoShift" in
def CheckMemScaled                      : CheckImmOperandSimple<4>;

// Check the shifting type in arithmetic and logic instructions.
let FunctionMapper = "AArch64_AM::getShiftType" in {
  def CheckShiftLSL                : CheckImmOperand_s<3, "AArch64_AM::LSL">;
  def CheckShiftLSR                : CheckImmOperand_s<3, "AArch64_AM::LSR">;
  def CheckShiftASR                : CheckImmOperand_s<3, "AArch64_AM::ASR">;
  def CheckShiftROR                : CheckImmOperand_s<3, "AArch64_AM::ROR">;
  def CheckShiftMSL                : CheckImmOperand_s<3, "AArch64_AM::MSL">;
}

// Check for shifting in arithmetic and logic instructions.
foreach I = {0-4, 8} in {
  let FunctionMapper = "AArch64_AM::getShiftValue" in
  def CheckShiftBy#I        : CheckImmOperand<3, I>;
}

// Generic predicates.
// Identify whether an instruction is NEON or floating point
def CheckFpOrNEON : CheckFunctionPredicateWithTII<
  "AArch64_MC::isFpOrNEON",
  "AArch64InstrInfo::isFpOrNEON"
>;

// Identify whether an instruction is the 128-bit NEON form based on its result.
def CheckQForm : CheckFunctionPredicateWithTII<
  "AArch64_MC::isQForm",
  "AArch64InstrInfo::isQForm"
>;

// Identify arithmetic instructions with extend.
def IsArithExtOp           : CheckOpcode<[ADDWrx, ADDXrx, ADDSWrx, ADDSXrx,
                                          SUBWrx, SUBXrx, SUBSWrx, SUBSXrx,
                                          ADDXrx64, ADDSXrx64,
                                          SUBXrx64, SUBSXrx64]>;

// Identify arithmetic immediate instructions.
def IsArithImmOp           : CheckOpcode<[ADDWri, ADDXri, ADDSWri, ADDSXri,
                                          SUBWri, SUBXri, SUBSWri, SUBSXri]>;

// Identify arithmetic instructions with shift.
def IsArithShiftOp         : CheckOpcode<[ADDWrs, ADDXrs, ADDSWrs, ADDSXrs,
                                          SUBWrs, SUBXrs, SUBSWrs, SUBSXrs]>;

// Identify arithmetic instructions without shift.
def IsArithUnshiftOp       : CheckOpcode<[ADDWrr, ADDXrr, ADDSWrr, ADDSXrr,
                                          SUBWrr, SUBXrr, SUBSWrr, SUBSXrr]>;

// Identify logic immediate instructions.
def IsLogicImmOp           : CheckOpcode<[ANDWri, ANDXri,
                                          EORWri, EORXri,
                                          ORRWri, ORRXri]>;

// Identify logic instructions with shift.
def IsLogicShiftOp         : CheckOpcode<[ANDWrs, ANDXrs, ANDSWrs, ANDSXrs,
                                          BICWrs, BICXrs, BICSWrs, BICSXrs,
                                          EONWrs, EONXrs,
                                          EORWrs, EORXrs,
                                          ORNWrs, ORNXrs,
                                          ORRWrs, ORRXrs]>;

// Identify logic instructions without shift.
def IsLogicUnshiftOp       : CheckOpcode<[ANDWrr, ANDXrr, ANDSWrr, ANDSXrr,
                                          BICWrr, BICXrr, BICSWrr, BICSXrr,
                                          EONWrr, EONXrr,
                                          EORWrr, EORXrr,
                                          ORNWrr, ORNXrr,
                                          ORRWrr, ORRXrr]>;

// Identify arithmetic and logic immediate instructions.
def IsArithLogicImmOp      : CheckOpcode<!listconcat(IsArithImmOp.ValidOpcodes,
                                                     IsLogicImmOp.ValidOpcodes)>;

// Identify arithmetic and logic instructions with shift.
def IsArithLogicShiftOp    : CheckOpcode<!listconcat(IsArithShiftOp.ValidOpcodes,
                                                     IsLogicShiftOp.ValidOpcodes)>;

// Identify arithmetic and logic instructions without shift.
def IsArithLogicUnshiftOp  : CheckOpcode<!listconcat(IsArithUnshiftOp.ValidOpcodes,
                                                     IsLogicUnshiftOp.ValidOpcodes)>;

// Identify whether an instruction is an ASIMD
// load using the post index addressing mode.
def IsLoadASIMDPostOp      : CheckOpcode<[LD1Onev8b_POST, LD1Onev4h_POST, LD1Onev2s_POST, LD1Onev1d_POST,
                                          LD1Onev16b_POST, LD1Onev8h_POST, LD1Onev4s_POST, LD1Onev2d_POST,
                                          LD1Twov8b_POST, LD1Twov4h_POST, LD1Twov2s_POST, LD1Twov1d_POST,
                                          LD1Twov16b_POST, LD1Twov8h_POST, LD1Twov4s_POST, LD1Twov2d_POST,
                                          LD1Threev8b_POST, LD1Threev4h_POST, LD1Threev2s_POST, LD1Threev1d_POST,
                                          LD1Threev16b_POST, LD1Threev8h_POST, LD1Threev4s_POST, LD1Threev2d_POST,
                                          LD1Fourv8b_POST, LD1Fourv4h_POST, LD1Fourv2s_POST, LD1Fourv1d_POST,
                                          LD1Fourv16b_POST, LD1Fourv8h_POST, LD1Fourv4s_POST, LD1Fourv2d_POST,
                                          LD1i8_POST, LD1i16_POST, LD1i32_POST, LD1i64_POST,
                                          LD1Rv8b_POST, LD1Rv4h_POST, LD1Rv2s_POST, LD1Rv1d_POST,
                                          LD1Rv16b_POST, LD1Rv8h_POST, LD1Rv4s_POST, LD1Rv2d_POST,
                                          LD2Twov8b_POST, LD2Twov4h_POST, LD2Twov2s_POST,
                                          LD2Twov16b_POST, LD2Twov8h_POST, LD2Twov4s_POST, LD2Twov2d_POST,
                                          LD2i8_POST, LD2i16_POST, LD2i32_POST, LD2i64_POST,
                                          LD2Rv8b_POST, LD2Rv4h_POST, LD2Rv2s_POST, LD2Rv1d_POST,
                                          LD2Rv16b_POST, LD2Rv8h_POST, LD2Rv4s_POST, LD2Rv2d_POST,
                                          LD3Threev8b_POST, LD3Threev4h_POST, LD3Threev2s_POST,
                                          LD3Threev16b_POST, LD3Threev8h_POST, LD3Threev4s_POST, LD3Threev2d_POST,
                                          LD3i8_POST, LD3i16_POST, LD3i32_POST, LD3i64_POST,
                                          LD3Rv8b_POST, LD3Rv4h_POST, LD3Rv2s_POST, LD3Rv1d_POST,
                                          LD3Rv16b_POST, LD3Rv8h_POST, LD3Rv4s_POST, LD3Rv2d_POST,
                                          LD4Fourv8b_POST, LD4Fourv4h_POST, LD4Fourv2s_POST,
                                          LD4Fourv16b_POST, LD4Fourv8h_POST, LD4Fourv4s_POST, LD4Fourv2d_POST,
                                          LD4i8_POST, LD4i16_POST, LD4i32_POST, LD4i64_POST,
                                          LD4Rv8b_POST, LD4Rv4h_POST, LD4Rv2s_POST, LD4Rv1d_POST,
                                          LD4Rv16b_POST, LD4Rv8h_POST, LD4Rv4s_POST, LD4Rv2d_POST]>;

// Identify whether an instruction is an ASIMD
// store using the post index addressing mode.
def IsStoreASIMDPostOp     : CheckOpcode<[ST1Onev8b_POST, ST1Onev4h_POST, ST1Onev2s_POST, ST1Onev1d_POST,
                                          ST1Onev16b_POST, ST1Onev8h_POST, ST1Onev4s_POST, ST1Onev2d_POST,
                                          ST1Twov8b_POST, ST1Twov4h_POST, ST1Twov2s_POST, ST1Twov1d_POST,
                                          ST1Twov16b_POST, ST1Twov8h_POST, ST1Twov4s_POST, ST1Twov2d_POST,
                                          ST1Threev8b_POST, ST1Threev4h_POST, ST1Threev2s_POST, ST1Threev1d_POST,
                                          ST1Threev16b_POST, ST1Threev8h_POST, ST1Threev4s_POST, ST1Threev2d_POST,
                                          ST1Fourv8b_POST, ST1Fourv4h_POST, ST1Fourv2s_POST, ST1Fourv1d_POST,
                                          ST1Fourv16b_POST, ST1Fourv8h_POST, ST1Fourv4s_POST, ST1Fourv2d_POST,
                                          ST1i8_POST, ST1i16_POST, ST1i32_POST, ST1i64_POST,
                                          ST2Twov8b_POST, ST2Twov4h_POST, ST2Twov2s_POST,
                                          ST2Twov16b_POST, ST2Twov8h_POST, ST2Twov4s_POST, ST2Twov2d_POST,
                                          ST2i8_POST, ST2i16_POST, ST2i32_POST, ST2i64_POST,
                                          ST3Threev8b_POST, ST3Threev4h_POST, ST3Threev2s_POST,
                                          ST3Threev16b_POST, ST3Threev8h_POST, ST3Threev4s_POST, ST3Threev2d_POST,
                                          ST3i8_POST, ST3i16_POST, ST3i32_POST, ST3i64_POST,
                                          ST4Fourv8b_POST, ST4Fourv4h_POST, ST4Fourv2s_POST,
                                          ST4Fourv16b_POST, ST4Fourv8h_POST, ST4Fourv4s_POST, ST4Fourv2d_POST,
                                          ST4i8_POST, ST4i16_POST, ST4i32_POST, ST4i64_POST]>;

// Identify whether an instruction is an ASIMD load
// or store using the post index addressing mode.
def IsLoadStoreASIMDPostOp : CheckOpcode<!listconcat(IsLoadASIMDPostOp.ValidOpcodes,
                                                     IsStoreASIMDPostOp.ValidOpcodes)>;

// Identify whether an instruction is a load
// using the register offset addressing mode.
def IsLoadRegOffsetOp      : CheckOpcode<[PRFMroW, PRFMroX,
                                          LDRBBroW, LDRBBroX,
                                          LDRSBWroW, LDRSBWroX, LDRSBXroW, LDRSBXroX,
                                          LDRHHroW, LDRHHroX,
                                          LDRSHWroW, LDRSHWroX, LDRSHXroW, LDRSHXroX,
                                          LDRWroW, LDRWroX,
                                          LDRSWroW, LDRSWroX,
                                          LDRXroW, LDRXroX,
                                          LDRBroW, LDRBroX,
                                          LDRHroW, LDRHroX,
                                          LDRSroW, LDRSroX,
                                          LDRDroW, LDRDroX,
                                          LDRQroW, LDRQroX]>;

// Identify whether an instruction is a store
// using the register offset addressing mode.
def IsStoreRegOffsetOp     : CheckOpcode<[STRBBroW, STRBBroX,
                                          STRHHroW, STRHHroX,
                                          STRWroW, STRWroX,
                                          STRXroW, STRXroX,
                                          STRBroW, STRBroX,
                                          STRHroW, STRHroX,
                                          STRSroW, STRSroX,
                                          STRDroW, STRDroX,
                                          STRQroW, STRQroX]>;

// Identify whether an instruction is a load or
// store using the register offset addressing mode.
def IsLoadStoreRegOffsetOp : CheckOpcode<!listconcat(IsLoadRegOffsetOp.ValidOpcodes,
                                                     IsStoreRegOffsetOp.ValidOpcodes)>;

// Target predicates.

// Identify an instruction that effectively transfers a register to another.
def IsCopyIdiomFn     : TIIPredicate<"isCopyIdiom",
                                     MCOpcodeSwitchStatement<
                                       [// MOV {Rd, SP}, {SP, Rn} =>
                                        // ADD {Rd, SP}, {SP, Rn}, #0
                                        MCOpcodeSwitchCase<
                                          [ADDWri, ADDXri],
                                          MCReturnStatement<
                                            CheckAll<
                                              [CheckIsRegOperand<0>,
                                               CheckIsRegOperand<1>,
                                               CheckAny<
                                                 [CheckRegOperand<0, WSP>,
                                                  CheckRegOperand<0, SP>,
                                                  CheckRegOperand<1, WSP>,
                                                  CheckRegOperand<1, SP>]>,
                                               CheckZeroOperand<2>]>>>,
                                        // MOV Rd, Rm =>
                                        // ORR Rd, ZR, Rm, LSL #0
                                        MCOpcodeSwitchCase<
                                          [ORRWrs, ORRXrs],
                                          MCReturnStatement<
                                            CheckAll<
                                              [CheckIsRegOperand<1>,
                                               CheckIsRegOperand<2>,
                                               CheckAny<
                                                 [CheckRegOperand<1, WZR>,
                                                  CheckRegOperand<1, XZR>]>,
                                               CheckShiftBy0]>>>],
                                       MCReturnStatement<FalsePred>>>;
def IsCopyIdiomPred   : MCSchedPredicate<IsCopyIdiomFn>;

// Identify arithmetic instructions with an extended register.
def RegExtendedFn     : TIIPredicate<"hasExtendedReg",
                                     MCOpcodeSwitchStatement<
                                       [MCOpcodeSwitchCase<
                                         IsArithExtOp.ValidOpcodes,
                                         MCReturnStatement<
                                           CheckNot<CheckZeroOperand<3>>>>],
                                       MCReturnStatement<FalsePred>>>;
def RegExtendedPred   : MCSchedPredicate<RegExtendedFn>;

// Identify arithmetic and logic instructions with a shifted register.
def RegShiftedFn      : TIIPredicate<"hasShiftedReg",
                                     MCOpcodeSwitchStatement<
                                       [MCOpcodeSwitchCase<
                                          IsArithLogicShiftOp.ValidOpcodes,
                                          MCReturnStatement<
                                            CheckNot<CheckZeroOperand<3>>>>],
                                       MCReturnStatement<FalsePred>>>;
def RegShiftedPred    : MCSchedPredicate<RegShiftedFn>;

// Identify a load or store using the register offset addressing mode
// with an extended or scaled register.
def ScaledIdxFn       : TIIPredicate<"isScaledAddr",
                                     MCOpcodeSwitchStatement<
                                       [MCOpcodeSwitchCase<
                                          IsLoadStoreRegOffsetOp.ValidOpcodes,
                                          MCReturnStatement<
                                            CheckAny<[CheckNot<CheckMemExtLSL>,
                                                      CheckMemScaled]>>>],
                                       MCReturnStatement<FalsePred>>>;
def ScaledIdxPred     : MCSchedPredicate<ScaledIdxFn>;

// Identify an instruction that effectively resets a FP register to zero.
def IsZeroFPIdiomFn   : TIIPredicate<"isZeroFPIdiom",
                                     MCOpcodeSwitchStatement<
                                       [// MOVI Vd, #0
                                        MCOpcodeSwitchCase<
                                          [MOVIv8b_ns, MOVIv16b_ns,
                                           MOVID, MOVIv2d_ns],
                                          MCReturnStatement<CheckZeroOperand<1>>>,
                                        // MOVI Vd, #0, LSL #0
                                        MCOpcodeSwitchCase<
                                          [MOVIv4i16, MOVIv8i16,
                                           MOVIv2i32, MOVIv4i32],
                                          MCReturnStatement<
                                            CheckAll<
                                              [CheckZeroOperand<1>,
                                               CheckZeroOperand<2>]>>>],
                                       MCReturnStatement<FalsePred>>>;
def IsZeroFPIdiomPred : MCSchedPredicate<IsZeroFPIdiomFn>;

// Identify an instruction that effectively resets a GP register to zero.
def IsZeroIdiomFn     : TIIPredicate<"isZeroIdiom",
                                    MCOpcodeSwitchStatement<
                                      [// ORR Rd, ZR, #0
                                       MCOpcodeSwitchCase<
                                         [ORRWri, ORRXri],
                                         MCReturnStatement<
                                           CheckAll<
                                             [CheckIsRegOperand<1>,
                                              CheckAny<
                                                [CheckRegOperand<1, WZR>,
                                                 CheckRegOperand<1, XZR>]>,
                                              CheckZeroOperand<2>]>>>],
                                      MCReturnStatement<FalsePred>>>;
def IsZeroIdiomPred   : MCSchedPredicate<IsZeroIdiomFn>;
